ํธ๋ฆฌ๋ ๋น์์ฐจ์ ์๋ฃ๊ตฌ์กฐ๋ก, ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ์ถ์ํํ ๋ชจ๋ธ์ด๋ค.
๊ฐ์ฅ ํํ ์์๋ก๋ ๊ฐ๊ณ๋ ํน์ ํ์ฌ ์กฐ์ง ๊ตฌ์กฐ ์ ๋๋ฅผ ๋ ์ฌ๋ฆด ์ ์๋ค.
ํธ๋ฆฌ๋ ๋ถ๋ชจ-์์ ๊ด๊ณ๋ฅผ ๊ฐ์ง ๋ค์์ ๋ ธ๋๋ก ๊ตฌ์ฑ๋๋ค. ์ต์์ ๋ ธ๋์ธ ๋ฃจํธ(root)๋ฅผ ์ ์ธํ ๋ชจ๋ ๋ ธํธ๋ ๋ถ๋ชจ ๋ ธ๋๋ฅผ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ๋ค์์ ์์ ๋ ธ๋๋ฅผ ๊ฐ์ง ์๋ ์๊ณ , ์์ ์์ ์๋ ์๋ค.
-
๋ฃจํธ(root): ์ต์์ ๋ ธ๋, ๋ถ๋ชจ๊ฐ ์๋ ๋ ธ๋
-
๋ด๋ถ ๋ ธ๋: ์์์ด ํ๋ ์ด์์ด ์กด์ฌํ๋ ๋ ธ๋
-
์ธ๋ถ ๋ ธ๋(leaf): ์์์ด ์กด์ฌํ์ง ์๋ ๋ ธ๋
-
์กฐ์: ๋ฃจํธ ๋ ธ๋๋ฅผ ์ ์ธํ ์์ ๋ ธ๋๋ฅผ ์ผ์ปซ๋๋ค.
-
ํ์: ์กฐ์๊ณผ ๋ฐ๋๋ก ํ์ ๋ ธ๋๋ฅผ ์ผ์ปซ๋๋ค.
-
์๋ธ ํธ๋ฆฌ: ๋ ธ๋์ ํ์์ผ๋ก ์ด๋ฃจ์ด์ง ํ ์์ ์์ ํธ๋ฆฌ
-
๊น์ด: ์กฐ์์ ๊ฐ์, ๋ ๋ฒจ๋ก ๊ตฌ๋ถ ํ๊ธฐ๋ ํจ
-
๋์ด: ๊น์ด์ ์ต๋์น
์ด์ง ํธ๋ฆฌ(binary tree): ์ข, ์ฐ์ธก์ ๊ฐ๊ฐ ํ๋์ฉ ํ์ฌ ์ต๋ ๋ ๊ฐ์ ์์ ๋ ธ๋๋ฅผ ๊ฐ์ง ํธ๋ฆฌ
์ด์ง ํ์ ํธ๋ฆฌ(binary search tree): ์ด์ง ํธ๋ฆฌ์์ ์ข์ธก ์์ ๋ ธ๋์๋ ์์ ๊ฐ์, ์ฐ์ธก ์์ ๋ ธ๋์๋ ๋ ํฐ ๊ฐ์ ๋ค๊ณ ์๋ค๋ ๊ท์น์ด ์ถ๊ฐ๋ ํธ๋ฆฌ
function Node(key) {
this.key = key;
this.left = null; // ์ข์ธก ์์ ๋
ธ๋
this.right = null; // ์ฐ์ธก ์์ ๋
ธ๋
}
function BinarySearchTree() {
let root = null; // ์ต์๋จ ๋
ธ๋
}
function BinarySearchTree() {
let root = null;
this.insert = function (key) {
const newNode = new Node(key);
if (root === null) {
// ๋ฃจํธ๊ฐ ์์ ๊ฒฝ์ฐ, ๋
ธ๋๋ฅผ ๋ฃจํธ๋ก ์ง์
root = newNode;
} else {
// ๊ทธ ์ธ ๋
ธ๋ ์ฝ์
insertNode(root, newNode);
}
};
}
function insertNode(node, newNode) {
// ์๋ก์ด ๋
ธ๋์ key๊ฐ๋ณด๋ค ํ์ฌ ๋
ธ๋์ key๊ฐ์ด ํด ๊ฒฝ์ฐ
if (newNode.key < node.key) {
// ๋
ธ๋์ ์ข์ธก ์์ ๋
ธ๋๊ฐ ๋น์ด์์ ๊ฒฝ์ฐ ์ง์
if (node.left === null) {
node.left = newNode;
} else {
// ๋น์ด์์ง ์์ ๊ฒฝ์ฐ ์ข์ธก ์์ ๋
ธ๋๋ฅผ ๋์์ผ๋ก ์ฌ๊ท ํธ์ถ
insertNode(node.left, newNode);
}
} else {
// ๋
ธ๋์ ์ฐ์ธก ์์ ๋
ธ๋๊ฐ ๋น์ด์์ ๊ฒฝ์ฐ ์ง์
if (node.right === null) {
node.right = newNode;
} else {
// ๋น์ด์์ง ์์ ๊ฒฝ์ฐ ์ฐ์ธก ์์ ๋
ธ๋๋ฅผ ๋์์ผ๋ก ์ฌ๊ท ํธ์ถ
insertNode(node.right, newNode);
}
}
}
ํธ๋ฆฌ์ ์ํ๋, ๋ชจ๋ ๋ ธ๋๋ฅผ ๋ฐฉ๋ฌธํ์ฌ ์ด๋ ํ ์์ ์ ์ํํ๋ ๊ฒ์ ํธ๋ฆฌ ์ํ๋ผ๊ณ ํ๋ค.
ํธ๋ฆฌ์ ์ํ ๋ฐฉ๋ฒ์๋ ์ธ ๊ฐ์ง๊ฐ ์๋ค.
์ค์ ์ํ๋ ๋ ธ๋๋ฅผ ์ค๋ฆ์ฐจ์, ์ฆ ์์ ๊ฐ์์ ํฐ ๊ฐ ์์๋๋ก ๋ฐฉ๋ฌธํ๋ ๋ฐฉ๋ฒ์ด๋ค.
function inOrderTraverseNode(node, callback) {
// ๋
ธ๋๊ฐ null์ด๋ผ๋ฉด ์ฌ๊ท ํธ์ถ์ ์ค๋จํ๋ค
if (node === null) return;
// ์ข์ธก ์์ ๋
ธ๋๋ฅผ ๋จผ์ ๋ฐฉ๋ฌธ
inOrderTraverseNode(node.left, callback);
// ํ์ฌ ๋
ธ๋๋ฅผ ๋ฐฉ๋ฌธ
callback(node.key);
// ์ฐ์ธก ๋
ธ๋๋ฅผ ๋ฐฉ๋ฌธ
inOrderTraverseNode(node.right, callback);
}
์ค์ ์ํ๋ฅผ ํตํด ๊ฐ์ ์ถ๋ ฅํ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ๋ค.
H D I B E A F C G
์ ์ ์ํ๋ ์์ ๋ ธ๋๋ณด๋ค ์๊ธฐ ์์ ์ ๋จผ์ ๋ฐฉ๋ฌธํ๋ ๋ฐฉ๋ฒ์ด๋ค.
function preOrderTraverseNode(node, callback) {
// ๋
ธ๋๊ฐ null์ด๋ผ๋ฉด ์ฌ๊ท ํธ์ถ์ ์ค๋จํ๋ค
if (node === null) return;
// ํ์ฌ ๋
ธ๋๋ฅผ ๋จผ์ ๋ฐฉ๋ฌธ
callback(node.key);
// ์ข์ธก ๋
ธ๋๋ฅผ ๋ฐฉ๋ฌธ
preOrderTraverseNode(node.left, callback);
// ์ฐ์ธก ๋
ธ๋๋ฅผ ๋ฐฉ๋ฌธ
preOrderTraverseNode(node.right, callback);
}
์ ์ ์ํ๋ฅผ ํตํด ๊ฐ์ ์ถ๋ ฅํ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ๋ค.
A B D H I E C F G
ํ์ ์ํ๋ ์์ ๋ ธ๋๋ฅผ ๋ชจ๋ ๋ฐฉ๋ฌธํ ๋ค ์๊ธฐ ์์ ์ ๋ฐฉ๋ฌธํ๋ ๋ฐฉ๋ฒ์ด๋ค.
function postOrderTraverseNode(node, callback) {
// ๋
ธ๋๊ฐ null์ด๋ผ๋ฉด ์ฌ๊ท ํธ์ถ์ ์ค๋จํ๋ค
if (node === null) return;
// ์ข์ธก ๋
ธ๋๋ฅผ ๋จผ์ ๋ฐฉ๋ฌธ
postOrderTraverseNode(node.left, callback);
// ์ฐ์ธก ๋
ธ๋๋ฅผ ๋ฐฉ๋ฌธ
postOrderTraverseNode(node.right, callback);
// ํ์ฌ ๋
ธ๋๋ฅผ ๋ฐฉ๋ฌธ
callback(node.key);
}
ํ์ ์ํ๋ฅผ ํตํด ๊ฐ์ ์ถ๋ ฅํ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ๋ค.
H I D E B F G C A
ํธ๋ฆฌ๋ฅผ ๊ฒ์ํ๋ ๋ฐฉ๋ฒ์๋ ์ธ ๊ฐ์ง๊ฐ ์๋ค.
์ด์ง ํ์ ํธ๋ฆฌ์ ํน์ง์ ์ ๋ณด๋ฉด, ์ต์๊ฐ ํน์ ์ต๋๊ฐ์ ํ ๋์ ์ ์ ์๋ค.
์ตํ์ ๋ ๋ฒจ์ ๋งจ ์ข์ธก ๋ ธ๋๊ฐ ์ต์๊ฐ, ์ตํ์ ๋ ๋ฒจ์ ๋งจ ์ฐ์ธก ๋ ธ๋๊ฐ ์ต๋๊ฐ์ด๋ค.
function minNode(node) {
if (!node) return null;
while (node.left !== null) {
node = node.left;
}
return node.key;
}
function maxNode(node) {
if (!node) return null;
while (node.right !== null) {
node = node.right;
}
return node.key;
}
๊ฐ๊ฐ์ ๋ฉ์๋๋ ๊ธฐ์ค์ด ๋ node๋ฅผ ๋๊ฒจ๋ฐ๋๋ฐ, ์ด๋ฐ ์์ผ๋ก ํธ๋ฆฌ ํน์ ์๋ธํธ๋ฆฌ์ ์ต์, ์ต๋๊ฐ์ ๊ตฌํ ์ ์๋ค.
function searchNode(node, key) {
// ๋
ธ๋๊ฐ ์์ ๊ฒฝ์ฐ false
if (node === null) return false;
// ํน์ ๊ฐ์ด ํ์ฌ ๋
ธ๋๋ณด๋ค ์์ ๊ฒฝ์ฐ
if (key < node.key) {
return searchNode(node.left, key);
}
// ํน์ ๊ฐ์ด ํ์ฌ ๋
ธ๋๋ณด๋ค ํด ๊ฒฝ์ฐ
else if (node.key < key) {
return searchNode(node.right, key);
}
// ํ์ฌ ๋
ธ๋๊ฐ ํน์ ๊ฐ์ผ ๊ฒฝ์ฐ
return true;
}
์๋ง ๊ฐ์ฅ ๋ณต์กํ ๋ฏ
function removeNode(node, key) {
if (node === null) return null;
// ํน์ ๊ฐ์ด ํ์ฌ ๋
ธ๋๋ณด๋ค ์์ ๊ฒฝ์ฐ
if (key < node.key) {
node.left = removeNode(node.left, key);
return node;
}
// ํน์ ๊ฐ์ด ํ์ฌ ๋
ธ๋๋ณด๋ค ํด ๊ฒฝ์ฐ
if (node.key < key) {
node.right = removeNode(node.right, key);
return node;
}
// ํ์ฌ ๋
ธ๋๊ฐ ํน์ ๊ฐ์ผ ๊ฒฝ์ฐ
// 1. ํ์ฌ ๋
ธ๋๊ฐ ๋ฆฌํ ๋
ธ๋์ผ ๊ฒฝ์ฐ
if (node.left === null && node.right === null) {
// ๋น ๋
ธ๋(null)๋ฅผ ๋ฐํํ๋ค
return null;
}
// 2. ์์์ด ํ๋ ์๋ ๋
ธ๋์ผ ๊ฒฝ์ฐ
if (node.left === null || node.right === null) {
// ๋น์ด์์ง ์์ ๋
ธ๋๋ฅผ ๋ฐํํ๋ค.
return node.left || node.right;
}
// 3. ์์์ด ๋์ธ ๋
ธ๋์ผ ๊ฒฝ์ฐ
// ์ฐ์ธก ์๋ธํธ๋ฆฌ์ ์ต์๊ฐ ๊ฒ์
const changeData = minNode(node.right);
// ํ์ฌ ๋
ธ๋์ ๊ฐ์ ์๋ธํธ๋ฆฌ์ ์ต์๊ฐ์ผ๋ก ๊ต์ฒด
node.key = changeData.key;
// ์ฐ์ธก ์๋ธํธ๋ฆฌ์์ ์ค๋ณต ๋ฐ์ดํฐ ์ ๊ฑฐ
node.right = removeNode(node.right, changeData.key);
// ํ์ฌ ๋
ธ๋ ๋ฐํ
return node;
}